Longest repeating substring [Rabin-Karp Algorithm]

Time: O(NLogN); Space: O(N); medium

Given a string S, find out the length of the longest repeating substring(s). Return 0 if no repeating substring exists.

Example 1:

Input: S = “abcd”

Output: 0

Explanation:

  • There is no repeating substring.

Example 2:

Input: S = “abbaba”

Output: 2

Explanation:

  • The longest repeating substrings are “ab” and “ba”, each of which occurs twice.

Example 3:

Input: S = “aabcaabdaab”

Output: 3

Explanation:

  • The longest repeating substring is “aab”, which occurs 3 times.

Example 4:

Input: S = “aaaaa”

Output: 4

Explanation:

  • The longest repeating substring is “aaaa”, which occurs twice.

Constraints:

  • The string S consists of only lowercase English letters from ‘a’ - ‘z’.

  • 1 <= len(S) <= 1500

1. Binary Search [O(NLogN), O(N)]

[3]:
import collections
import functools

class Solution1(object):
    """
    Time: O(NLogN), N = len(S)
    Space: O(N)
    """
    def longestRepeatingSubstring(self, S):
        """
        :type S: str
        :rtype: int
        """
        M = 10**9+7
        D = 26

        def check(S, L):
            p = pow(D, L, M)
            curr = functools.reduce(lambda x, y: (D*x+ord(y)-ord('a')) % M, S[:L], 0)
            lookup = collections.defaultdict(list)
            lookup[curr].append(L-1)
            result = 0

            for i in range(L, len(S)):

                curr = ((D*curr) % M + ord(S[i])-ord('a') -
                        ((ord(S[i-L])-ord('a'))*p) % M) % M

                if curr in lookup:
                    for j in lookup[curr]:
                        if S[j-L+1:j+1] == S[i-L+1:i+1]:
                            if result == 0:
                                result = i
                            return result-L+1
                lookup[curr].append(i)
            return result

        left, right = 0, len(S)-1

        while left <= right:
            mid = left + (right-left) // 2
            if not check(S, mid):
                right = mid - 1
            else:
                left = mid + 1

        return right
[4]:
s = Solution1()

S = "abcd"
assert s.longestRepeatingSubstring(S) == 0

S = "abbaba"
assert s.longestRepeatingSubstring(S) == 2

S = "aabcaabdaab"
assert s.longestRepeatingSubstring(S) == 3

S = "aaaaa"
assert s.longestRepeatingSubstring(S) == 4